package com.wallet.controller;

import com.alibaba.fastjson.JSON;
import com.wallet.constants.BusinessConstants;
import com.wallet.entity.WalletDetailsEntity;
import com.wallet.service.WalletDetailsService;
import com.wallet.util.R;
import com.wallet.util.RedisTradeIDGenerate;
import com.wallet.util.RedisUtil;
import com.wallet.vo.PayAsyncVo;
import org.apache.ibatis.annotations.Param;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;

/**
 * 钱包流水记录Controller
 * @author zhangguangyuang
 */
@RestController
public class WalletDetailsController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTradeIDGenerate redisTradeIDGenerate;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Resource
    private WalletDetailsService walletDetailsService;

    //订单号key
    private String PAY_CHARE_PREFIX="pay:orderNo";
    //订单号key
    private String REFUND_CHARE_PREFIX="refund:orderNo";


    /**
     * 用户消费100元
     * @param payAsyncVo 支付信息
     * @return
     */
    @PostMapping("/consumeHundred")
    public R consumeHundred(PayAsyncVo payAsyncVo){
        // 获取付款交易号
        String payOn = redisTradeIDGenerate.getTradeId(BusinessConstants.PAY_ON, 1L);
        // 设置付款有效期30秒
        redisUtil.set(BusinessConstants.PAY_OVER_TIME_KEY + payOn, 0, BusinessConstants.BUSINESS_OVER_TIME);
        payAsyncVo.setOutTradeNo(payOn);
        //消费信息发送到消息队列
        rabbitTemplate.convertAndSend("payment-event-exchange","pay.create.pay",payAsyncVo);
        return R.ok().put("data","付款中");
    }

    /**
     * 付款结果(由客户端轮询从redis缓存获取)
     * @param orderNo  订单号
     * @return
     */
    @GetMapping("/consumeHundredResult")
    public R consumeHundredResult(@Param("orderNo") String orderNo){
        R result = R.ok().put("data","付款中");
        //从redis缓存取出消费结果返回给客户端
        if(redisTemplate.opsForHash().hasKey(PAY_CHARE_PREFIX,orderNo)){
            String json = (String)redisTemplate.opsForHash().get(PAY_CHARE_PREFIX,orderNo);
            result = JSON.parseObject(json, R.class);
        }
        return result;

    }


    /**
     *  退款20元
     * @param payAsyncVo
     * @return
     */
    @PostMapping("/refund")
    public R refund(PayAsyncVo payAsyncVo){
        // 获取退款交易号
        String payOn = redisTradeIDGenerate.getTradeId(BusinessConstants.REFUND_ON, 1L);
        // 设置退款有效期30秒
        redisUtil.set(BusinessConstants.REFUND_OVER_TIME_KEY + payOn, 0, BusinessConstants.BUSINESS_OVER_TIME);
        payAsyncVo.setOutTradeNo(payOn);
        //消费信息发送到消息队列
        rabbitTemplate.convertAndSend("refund-event-exchange","refund.create.refund",payAsyncVo);
        return R.ok().put("data","退款中");
    }

    /**
     * 退款结果(由客户端轮询从redis缓存获取)
     * @param orderNo  订单号
     * @return
     */
    @GetMapping("/refundResult")
    public R refundResult(@Param("orderNo") String orderNo){
        R result = R.ok().put("data","退款中");
        //从redis缓存取出消费结果返回给客户端
        if(redisTemplate.opsForHash().hasKey(REFUND_CHARE_PREFIX,orderNo)){
            String json = (String)redisTemplate.opsForHash().get(REFUND_CHARE_PREFIX,orderNo);
            result = JSON.parseObject(json, R.class);
        }
        return result;
    }


    /**
     * 查询用户钱包金额变动明细
     * @param walletId   钱包id
     * @param startTime  开始时间
     * @param endTime    结束时间
     * @return
     */
    @GetMapping("/walletChangeDetails")
    public R getWalletDetailsChangeByWalletId(@Param("walletId") Integer walletId,@Param("startTime")String startTime,@Param("endTime")String endTime){
        //增加读写锁，防止读到旧数据
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(BusinessConstants.WALLET_READ_WRITE_LOCK_PREFIX+walletId);
        RLock rLock = readWriteLock.readLock();
        try{
            List<WalletDetailsEntity> details = walletDetailsService.getWalletDetailsByWalletIdAndStartTimeAndEndTime(walletId,startTime,endTime);
            return R.ok().put("data", details);
        }catch (Exception e){
            return R.error(13,"查询用户钱包金额变动明细失败，请重试");
        }finally {
            rLock.unlock();
        }
    }
}
